package cn.demoncat.util.lang.entity.report;

import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.lang.LocalDateUtil;
import cn.demoncat.util.lang.NumberUtil;
import cn.demoncat.util.lang.ObjectUtil;
import cn.demoncat.util.lang.StringUtil;
import cn.demoncat.util.lang.constant.*;
import cn.demoncat.util.lang.entity.MysqlQuery;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 日期图表参数（实时查询）
 *
 * 1、图表参数
 * 2、构建图表查询器
 * 3、处理图表结果数据，数据类应继承DateEntity或DateCountSum
 *
 * @author 延晓磊
 * @since 2021年11月25日
 */
@Data
public class DateChartParam {

    /**
     * 图表模式
     *
     * 分时图表：ReportConstant.ModeTime
     * 周期图表：ReportConstant.ModePeriod
     */
    private String mode;

    /* ==================== 分时图表 ModeTime ==================== */

    /**
     * 基准日期-年
     */
    private Integer year;
    /**
     * 基准日期-月
     */
    private Integer month;
    /**
     * 基准日期-日
     */
    private Integer day;
    /**
     * 最大值（忽略未来数据，非参数）
     */
    private Integer max;

    /* =================== 周期图表 ModePeriod ================ */

    /**
     * 周期数：最小为1
     */
    private Integer num;
    /**
     * 基准日期：结束周期
     */
    private LocalDateTime date;

    /* =================== 构建查询器 ================ */
 
    /**
     * 构建查询器
     *
     * 1、前提
     * 1.1 传参图表模式 mode = ReportConstant.ModeTime/ModePeriod
     * 1.2 根据图表模式，传参图表时间
     * 1.3 在mapper.xml的conditionWhere中，声明日期参数的start和end查询条件
     * 1.4 调用本方法
     *
     * 2、功能
     * 2.1 创建MysqlQuery
     * 2.2 在MysqlQuery.child中，以 dateColumn.between(startDateColumn,endDateColumn) 筛选数据时间区间
     * 2.3 在MysqlQuery.child中，以 dateColumn 格式化日期，输出 "date"
     * 2.4 在MysqlQuery中，以 "date" 进行分组
     *
     * 3、后续
     * 3.1 在MysqlQuery.child中，添加其它查询字段（如统计字段）和筛选条件
     * 3.2 在MysqlQuery中，添加查询字段，将MysqlQuery.child的查询字段（包含"date"）包装返回
     * 3.3 调用service.list(MysqlQuery)查询结果
     *
     * @param dateColumn	日期字段：数据时间筛选，日期格式化，日期分组
     * @return [date]
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    public MysqlQuery buildCountSumQuery(String dateColumn){
        // 图表模式
        if (StringUtils.isBlank(this.mode)) {
            throw new ParamRuntimeException("图表模式不能为空");
        }
        // 日期字段
        if (StringUtils.isBlank(dateColumn)) {
            throw new ParamRuntimeException("日期字段不能为空");
        }
        // 构建条件
        MysqlQuery query = new MysqlQuery();
        String startTime;
        String endTime;
        if (ReportConstant.ModeTime.MODE_TYPE.equals(StringUtil.get(this.mode, 0))) {
            // 分时表
            LocalDateTime now = LocalDateTime.now();
            LocalDate temp;
            if (this.year == null) {
                this.year = now.getYear();
            }
            if (this.month == null) {
                this.month = now.getMonthValue();
            }
            if (this.day == null) {
                this.day = now.getDayOfMonth();
            }
            switch (mode) {
                case ReportConstant.ModeTime.HOUR:
                    // 日.时
                    temp = LocalDate.of(this.year, this.month, this.day);
                    if (temp.isAfter(now.toLocalDate())) {
                        throw new ParamRuntimeException("日期不能大于当前");
                    }else if (temp.isEqual(now.toLocalDate())) {
                        this.max = now.getHour();
                    }
                    startTime = LocalDateUtil.toStr(temp);
                    endTime = LocalDateUtil.toStr(temp.plusDays(1));
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.HOUR).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModeTime.DAY:
                    // 月.日
                    temp = LocalDate.of(this.year, this.month, 1);
                    if (temp.isAfter(now.toLocalDate().withDayOfMonth(1))) {
                        throw new ParamRuntimeException("日期不能大于当前");
                    }else if (temp.isEqual(now.toLocalDate().withDayOfMonth(1))) {
                        this.max = now.getDayOfMonth();
                    }
                    startTime = LocalDateUtil.format(now, DateConstant.MONTH_FORMAT);
                    endTime = LocalDateUtil.format(now.plusMonths(1), DateConstant.MONTH_FORMAT);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.DAY).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModeTime.MONTH:
                    // 年.月
                    if (this.year > now.getYear()) {
                        throw new ParamRuntimeException("日期不能大于当前");
                    }else if (this.year == now.getYear()) {
                        this.max = now.getMonthValue();
                    }
                    startTime = String.valueOf(this.year);
                    endTime = String.valueOf(this.year + 1);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.MONTH).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModeTime.QUARTER:
                    // 年.季
                    if (this.year > now.getYear()) {
                        throw new ParamRuntimeException("日期不能大于当前");
                    }else if (this.year == now.getYear()) {
                        this.max = LocalDateUtil.getQuarter(now.getMonthValue());
                    }
                    startTime = String.valueOf(this.year);
                    endTime = String.valueOf(this.year + 1);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnFunction(MysqlConstant.DateFunction.QUARTER, "date", dateColumn).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                default:
                    throw ReportConstant.CHART_MODE_ERROR;
            }
        }else{
            // 周期表
            if (this.num == null || this.num < 1) {
                throw ReportConstant.DYNAMIC_CHART_NUM_ERROR;
            }
            if (this.date == null) {
                this.date = LocalDateTime.now();
            }
            switch (mode) {
                case ReportConstant.ModePeriod.HOUR:
                    // 时
                    startTime = LocalDateUtil.format(this.date.minusHours(this.num -1), DateConstant.DATE_HOUR_FORMAT);
                    endTime = LocalDateUtil.format(this.date.plusHours(1), DateConstant.DATE_HOUR_FORMAT);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.DATE_HOUR).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModePeriod.DAY:
                    // 日
                    startTime = LocalDateUtil.format(this.date.minusDays(this.num -1), DateConstant.DATE_FROMAT);
                    endTime = LocalDateUtil.format(this.date.plusDays(1), DateConstant.DATE_FROMAT);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.DATE).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModePeriod.WEEK:
                    // 周：date = yyyy-01~53
                    this.date = LocalDateUtil.startOfWeek(this.date);
                    startTime = LocalDateUtil.format(this.date.minusWeeks(this.num -1), DateConstant.DATE_FROMAT);
                    endTime = LocalDateUtil.format(this.date.plusWeeks(1), DateConstant.DATE_FROMAT);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnFunction(MysqlConstant.DateFunction.YEAR_WEEK, "date", dateColumn, dateColumn).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModePeriod.MONTH:
                    // 月
                    startTime = LocalDateUtil.format(this.date.minusMonths(this.num -1), DateConstant.MONTH_FORMAT);
                    endTime = LocalDateUtil.format(this.date.plusMonths(1), DateConstant.MONTH_FORMAT);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.DATE_MONTH).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModePeriod.QUARTER:
                    // 季：date = yyyy-1~4
                    this.date = LocalDateUtil.startOfQuarter(this.date);
                    startTime = LocalDateUtil.format(LocalDateUtil.minusQuarter(this.date, this.num -1), DateConstant.MONTH_FORMAT);
                    endTime = LocalDateUtil.format(LocalDateUtil.plusQuarter(this.date, 1), DateConstant.MONTH_FORMAT);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnFunction(MysqlConstant.DateFunction.YEAR_QUARTER, "date", dateColumn, dateColumn).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                case ReportConstant.ModePeriod.YEAR:
                    // 年
                    startTime = String.valueOf(this.date.getYear() - this.num + 1);
                    endTime = String.valueOf(this.date.getYear() + 1);
                    return query.addGroup("date").addChild(new MysqlQuery().addColumnDate(dateColumn, MysqlConstant.DateFormat.YEAR).addCondition(getStartDateCondition(dateColumn), startTime, getEndDateCondition(dateColumn), endTime));
                default:
                    throw ReportConstant.CHART_MODE_ERROR;
            }
        }
    }

    /**
     * 构建查询器 - DateCountSum
     *
     * 1、前提
     * 1.1 传参图表模式 mode = ReportConstant.ModeTime/ModePeriod
     * 1.2 根据图表模式，传参图表时间
     * 1.3 在mapper.xml的conditionWhere中，声明日期参数的start和end查询条件
     * 1.4 调用本方法
     *
     * 2、功能
     * 2.1 创建MysqlQuery
     * 2.2 在MysqlQuery.child中，以 dateColumn.between(startDateColumn,endDateColumn) 筛选数据时间区间
     * 2.3 在MysqlQuery.child中，以 dateColumn 格式化日期，输出 "date"
     * 2.4 在MysqlQuery中，以 "date" 进行分组和排序
     * 2.5 在MysqlQuery中，返回 "date"、"COUNT(1) AS count"、"SUM(sumColumn) AS sum"
     *
     * 3、后续
     * 3.1 在MysqlQuery.child中，添加其它查询字段和筛选条件
     * 3.2 在MysqlQuery中，添加查询字段，将MysqlQuery.child的查询字段（默认返回"date"、"count"、"sum"）包装返回
     * 3.3 调用service.list(MysqlQuery)查询结果
     *
     * @param dateColumn	日期字段：数据时间筛选，日期格式化，日期分组
     * @param sumColumn	    金额字段：求和
     *
     * @return [date,count,sum]，可以使用 DateCount或DateCountSum接收
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    public MysqlQuery buildCountSumQuery(String dateColumn, String sumColumn){
        // 日期筛选
        MysqlQuery query = this.buildCountSumQuery(dateColumn);
        // 金额统计
        query.getChild().addColumn(sumColumn);
        query.addColumnCount().addColumnSum(sumColumn).addColumn("date").addOrder("date");
        return query;
    }

    /**
     * 构建查询器 - DateCount
     *
     * 1、前提
     * 1.1 传参图表模式 mode = ReportConstant.ModeTime/ModePeriod
     * 1.2 根据图表模式，传参图表时间
     * 1.3 在mapper.xml的conditionWhere中，声明日期参数的start和end查询条件
     * 1.3 调用本方法
     *
     * 2、功能
     * 2.1 创建MysqlQuery
     * 2.2 在MysqlQuery.child中，以 dateColumn.between(startDateColumn,endDateColumn) 筛选数据时间区间
     * 2.3 在MysqlQuery.child中，以 dateColumn 格式化日期，输出 "date"
     * 2.4 在MysqlQuery中，以 "date" 进行分组和排序
     * 2.5 在MysqlQuery中，返回 "date"、"COUNT(1) AS count""
     *
     * 3、后续
     * 3.1 在MysqlQuery.child中，添加其它查询字段和筛选条件
     * 3.2 在MysqlQuery中，添加查询字段，将MysqlQuery.child的查询字段（默认返回"date"、"count"）包装返回
     * 3.3 调用service.list(MysqlQuery)查询结果
     *
     * @param dateColumn	日期字段：数据时间筛选，日期格式化，日期分组
     *
     * @return [date,count]，可以使用 DateCount或DateCountSum接收
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    public MysqlQuery buildCountQuery(String dateColumn){
        // 日期筛选
        MysqlQuery query = this.buildCountSumQuery(dateColumn);
        // 金额统计
        query.addColumnCount().addColumn("date").addOrder("date");
        return query;
    }

    /**
     * 日期起始条件：dateColumn >= mapper.xml[conditionWhere.startDateColumn]
     */
    private static String getStartDateCondition(String dateColumn){
        // 日期字段转驼峰 > 首字段大写 > 前缀 "start"
        return "start" + StringUtil.firstUpper(StringUtil.parseLineToHump(dateColumn));
    }

    /**
     * 日期结束条件：dateColumn < mapper.xml[conditionWhere.endDateColumn]
     */
    private static String getEndDateCondition(String dateColumn){
        // 日期字段转驼峰 > 首字段大写 > 前缀 "end"
        return "end" + StringUtil.firstUpper(StringUtil.parseLineToHump(dateColumn));
    }

    /* =================== 转换图表结果 ================ */

    /**
     * 获取图表数据
     *
     * @param list      结果数据：{date}
     * @param chart     整合图表：{category}
     * @param filler    数据填充器
     * @return {category}
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    public <T extends DateEntity,R extends ChartEntity>R toDateChart(List<T> list, R chart, DateChartDataFiller<T,R> filler){
        if (ReportConstant.ModeTime.MODE_TYPE.equals(StringUtil.get(this.mode, 0))) {
            // 分时表
            return toTimeDateChart(list, chart, filler);
        }else{
            // 周期表
            return toPeriodDateChart(list, chart, filler);
        }
    }

    /**
     * 获取图表数据 - DateCountSum > CountSumChart
     *
     * @param list  结果数据：{date,count,sum}
     * @return {category,counts,sums}
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    public <T extends DateCountSum>CountSumChart toDateCountSumChart(List<T> list){
        return this.toDateChart(list, new CountSumChart(), new CountSumDateChartDataFiller<>());
    }

    /**
     * 获取图表数据 - DateCountTrade > CountTradeChart
     *
     * @param list  结果数据：{date,count,income,expend}
     * @return {category,counts,incomes,expends}
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    public <T extends DateCountTrade>CountTradeChart toDateCountTradeChart(List<T> list){
        return this.toDateChart(list, new CountTradeChart(), new CountTradeDateChartDataFiller<>());
    }

    /**
     * 获取分时图表 - 日期统计
     *
     * @param list      结果数据：{date}
     * @param chart     整合图表：{category}
     * @param filler    数据填充器
     * @return {category}
     * 
     * @author 延晓磊
     * @since 2021年11月25日
     */
    private <T extends DateEntity,R extends ChartEntity>R toTimeDateChart(List<T> list, R chart, DateChartDataFiller<T,R> filler) {
        // 数据
        Map<String, T> map = list.stream().collect(Collectors.toMap(DateEntity::getDate, o -> o));
        // 模式
        int max;
        switch (this.mode) {
            case ReportConstant.ModeTime.HOUR:
                // 日.时
                max = 23;
                break;
            case ReportConstant.ModeTime.DAY:
                // 月.日
                max = Month.of(this.month).maxLength();
                break;
            case ReportConstant.ModeTime.MONTH:
                // 年.月
                max = 12;
                break;
            case ReportConstant.ModeTime.QUARTER:
                // 年.季
                max = 4;
                break;
            default:
                throw ReportConstant.CHART_MODE_ERROR;
        }
        // 添加数据
        for (int i = 1; i <= max; i++) {
            this.addTimeDateChartData(map, chart, i, filler);
        }
        return chart;
    }

    /**
     * 添加分时图表的数据
     * 
     * @param map
     * @param chart
     * @param i
     * @param filler
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    private <T extends DateEntity,R extends ChartEntity>void addTimeDateChartData(Map<String, T> map, R chart, int i, DateChartDataFiller<T,R> filler){
        // 分组
        chart.getCategory().add(this.parseDate(String.valueOf(i)));
        // 数据，忽略未来数据
        if (this.max == null || this.max >= i) {
            // 获取数据，填充数据
            filler.fill(chart, map.get(String.valueOf(i)));
        }
    }

    /**
     * 获取周期图表 - 日期统计
     *
     * @param list      结果数据：{date}
     * @param chart     整合图表：{category}
     * @param filler    数据填充器
     * @return {category}
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    private <T extends DateEntity,R extends ChartEntity>R toPeriodDateChart(List<T> list, R chart, DateChartDataFiller<T,R> filler) {
        // 数据
        Map<String, T> map = list.stream().collect(Collectors.toMap(DateEntity::getDate, o -> o));
        // 模式
        LocalDateTime startTime;
        switch (this.mode) {
            case ReportConstant.ModePeriod.HOUR:
                // 时
                startTime = this.date.minusHours(this.num);
                for (int i = 0; i < this.num; i++) {
                    startTime = startTime.plusHours(1);
                    this.addPeriodDateChartData(map, chart, startTime.format(DateConstant.DATE_HOUR_FORMAT), filler);
                }
                break;
            case ReportConstant.ModePeriod.DAY:
                // 日
                startTime = this.date.minusDays(this.num);
                for (int i = 0; i < this.num; i++) {
                    startTime = startTime.plusDays(1);
                    this.addPeriodDateChartData(map, chart, startTime.format(DateConstant.DATE_FROMAT), filler);
                }
                break;
            case ReportConstant.ModePeriod.WEEK:
                // 周
                startTime = this.date.minusWeeks(this.num);
                for (int i = 0; i < this.num; i++) {
                    startTime = startTime.plusWeeks(1);
                    this.addPeriodDateChartData(map, chart, startTime.getYear() + StringConstant.BAR + NumberUtil.format(LocalDateUtil.getWeek(startTime.toLocalDate()), "00"), filler);
                }
                break;
            case ReportConstant.ModePeriod.MONTH:
                // 月
                startTime = this.date.minusMonths(this.num);
                for (int i = 0; i < this.num; i++) {
                    startTime = startTime.plusMonths(1);
                    this.addPeriodDateChartData(map, chart, startTime.format(DateConstant.MONTH_FORMAT), filler);
                }
                break;
            case ReportConstant.ModePeriod.QUARTER:
                // 季
                startTime = LocalDateUtil.minusQuarter(this.date, this.num);
                for (int i = 0; i < this.num; i++) {
                    startTime = LocalDateUtil.plusQuarter(startTime, 1);
                    this.addPeriodDateChartData(map, chart, startTime.getYear() + StringConstant.BAR + LocalDateUtil.getQuarter(startTime.getMonthValue()), filler);
                }
                break;
            case ReportConstant.ModePeriod.YEAR:
                // 年
                startTime = this.date.minusYears(this.num);
                for (int i = 0; i < this.num; i++) {
                    startTime = startTime.plusYears(1);
                    this.addPeriodDateChartData(map, chart, String.valueOf(startTime.getYear()), filler);
                }
                break;
            default:
                throw ReportConstant.CHART_MODE_ERROR;
        }
        return chart;
    }

    /**
     * 添加周期图表的数据
     *
     * @param map
     * @param chart
     * @param date
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    private <T extends DateEntity,R extends ChartEntity>void addPeriodDateChartData(Map<String, T> map, R chart, String date, DateChartDataFiller<T,R> filler){
        // 分组
        chart.getCategory().add(this.parseDate(date));
        // 获取数据，填充数据
        filler.fill(chart, map.get(date));
    }

    /**
     * 对date结果进行处理
     *
     * @param date  查询结果的date字段
     * @return
     *
     * @author 延晓磊
     * @since 2021年11月25日
     */
    private String parseDate(String date){
        switch (this.mode) {
            case ReportConstant.ModeTime.HOUR:
            case ReportConstant.ModePeriod.HOUR:
                // 日.时，周期.时
                return date + " 时";
            case ReportConstant.ModeTime.DAY:
                // 月.日
                return date + " 日";
            case ReportConstant.ModeTime.MONTH:
                // 年.月
                return date + " 月";
            case ReportConstant.ModeTime.QUARTER:
                // 年.季
                return DateConstant.QUARTER_MAP.get(date);
            case ReportConstant.ModePeriod.QUARTER:
                // 周期.季：yyyy-1~4 > 2019 春
                String[] quarters = date.split(StringConstant.BAR);
                return quarters[0] + StringConstant.SPACING + DateConstant.QUARTER_MAP.get(quarters[1]);
            case ReportConstant.ModePeriod.WEEK:
                // 周期.周：yyyy-01~53 > 2021-06-13 日
                String[] weeks = date.split(StringConstant.BAR);
                return LocalDateUtil.toStr(LocalDateUtil.toLocalDateByWeek(Integer.parseInt(weeks[0]), Integer.parseInt(weeks[1])));
            default:
                // 周期.日、月、年
                return date;
        }
    }

    /* =================== 图表结果数据填充器 ================ */

    /**
     * DateChart图表数据填充器
     * 
     * @author 延晓磊
     * @since 2021年11月26日
     */
    @FunctionalInterface
    public interface DateChartDataFiller<T extends DateEntity,R extends ChartEntity>{

        /**
         * 数据填充
         *
         * @param chart 图表对象
         * @param data  数据
         */
        void fill(R chart, T data);
    }

    /**
     * DateChart图表数据填充器 - DateCountSum
     *
     * @author 延晓磊
     * @since 2021年11月26日
     */
    public static class CountSumDateChartDataFiller<T extends DateCountSum, R extends CountSumChart> implements DateChartDataFiller<T, R>{

        @Override
        public void fill(R chart, T data) {
            if (data == null) {
                // 默认值
                chart.getCounts().add(LongConstant.N0);
                chart.getSums().add(StringConstant.N0);
            }else{
                // 计算值
                chart.getCounts().add(ObjectUtil.toDefault(data.getCount(), LongConstant.N0));
                chart.getSums().add(ObjectUtil.toDefault(data.getSum(), StringConstant.N0));
            }
        }
    }

    /**
     * DateChart图表数据填充器 - DateCountTrade
     *
     * @author 延晓磊
     * @since 2021年11月26日
     */
    public static class CountTradeDateChartDataFiller<T extends DateCountTrade, R extends CountTradeChart> implements DateChartDataFiller<T, R>{

        @Override
        public void fill(R chart, T data) {
            if (data == null) {
                // 默认值
                chart.getCounts().add(LongConstant.N0);
                chart.getIncomeSums().add(StringConstant.N0);
                chart.getExpendSums().add(StringConstant.N0);
                chart.getIncomeCounts().add(StringConstant.N0);
                chart.getExpendCounts().add(StringConstant.N0);
            }else{
                // 计算值
                chart.getCounts().add(ObjectUtil.toDefault(data.getCount(), LongConstant.N0));
                chart.getIncomeSums().add(ObjectUtil.toDefault(data.getIncomeSum(), StringConstant.N0));
                chart.getExpendSums().add(ObjectUtil.toDefault(data.getExpendSum(), StringConstant.N0));
                chart.getIncomeCounts().add(ObjectUtil.toDefault(data.getIncomeCount(), StringConstant.N0));
                chart.getExpendCounts().add(ObjectUtil.toDefault(data.getExpendCount(), StringConstant.N0));
            }
        }
    }

}
